import psutil
import socket
import subprocess
import time
import sys

# 配置
TARGET_HOST = '8.8.8.8'  # 测试目标
TARGET_PORT = 53  # DNS 端口
CHECK_INTERVAL = 60  # 检测间隔（秒）
TIMEOUT = 3  # 连接超时


def get_local_ips():
    """获取所有非回环 IPv4 地址"""
    interfaces = []
    for interface_name, addrs in psutil.net_if_addrs().items():
        for addr in addrs:
            if addr.family == socket.AF_INET:
                ip = addr.address
                if not ip.startswith('127.'):
                    netmask = addr.netmask
                    interfaces.append({
                        'interface': interface_name,
                        'ip': ip,
                        'netmask': netmask
                    })
    return interfaces


def is_online(ip: str) -> bool:
    """测试从指定 IP 是否能连接外网"""
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(TIMEOUT)
        sock.bind((ip, 0))
        result = sock.connect_ex((TARGET_HOST, TARGET_PORT))
        sock.close()
        return result == 0
    except:
        return False


def get_gateway_from_ip(ip: str) -> str:
    """
    简单推断网关（适用于 C 类网络如 192.168.x.1）
    实际生产中可结合 ARP 或路由表更精确获取
    """
    return '.'.join(ip.split('.')[:-1]) + '.1'


def set_default_route(interface_ip: str, interface_name: str):
    """简化版：设置默认路由，不依赖接口索引"""
    try:
        gateway = get_gateway_from_ip(interface_ip)
        print(f"🔧 尝试设置默认网关: {gateway} (通过网卡: {interface_name})")

        # 删除旧路由
        subprocess.run("route delete 0.0.0.0", shell=True)
        time.sleep(1)

        # 添加新路由（不指定 if）
        cmd = f'route add 0.0.0.0 mask 0.0.0.0 {gateway} metric 1'
        result = subprocess.run(cmd,
                                shell=True,
                                capture_output=True,
                                text=True,
                                encoding='gbk')

        if result.returncode == 0:
            print(f"✅ 成功设置路由：流量将通过 {interface_name} ({interface_ip})")
            return True
        else:
            print(f"❌ 路由失败: {result.stderr}")
            return False
    except Exception as e:
        print(f"❌ 错误: {e}")
        return False


def find_and_switch_to_working_interface():
    """查找可用网卡并切换路由"""
    interfaces = get_local_ips()
    if not interfaces:
        print("❌ 未检测到任何有效网卡")
        return False

    print(f"\n🔍 正在检测 {len(interfaces)} 个网卡...")
    for iface in interfaces:
        ip = iface['ip']
        print(f"  📡 测试 {iface['interface']} ({ip}) ... ", end="", flush=True)
        if is_online(ip):
            print("✅ 畅通")
            print(f"🎉 发现可用网卡: {iface['interface']} ({ip})")
            if set_default_route(ip, iface['interface']):
                return True
            else:
                print("⚠️  路由设置失败，尝试下一个...")
        else:
            print("❌ 不通")

    print("💔 所有网卡均无法连接外网")
    return False


def main():
    print("🚀 多网卡自动选路程序启动（按 Ctrl+C 退出）")
    print("💡 本程序将自动选择第一个能上网的网卡作为默认出口")

    # 检查是否以管理员权限运行（Windows）
    if sys.platform == "win32":
        import ctypes
        if not ctypes.windll.shell32.IsUserAnAdmin():
            print("❌ 错误：请以管理员身份运行此脚本（否则无法修改路由）")
            input("按回车键退出...")
            return

    while True:
        try:
            find_and_switch_to_working_interface()
            print(f"⏳ {CHECK_INTERVAL} 秒后再次检测...\n" + "-" * 60)
            time.sleep(CHECK_INTERVAL)
        except KeyboardInterrupt:
            print("\n👋 程序已退出")
            break
        except Exception as e:
            print(f"⚠️  发生异常: {e}")
            time.sleep(5)


if __name__ == "__main__":
    main()
